const {
  Connection,
  Keypair,
  PublicKey,
  Transaction,
  sendAndConfirmTransaction,
  LAMPORTS_PER_SOL,
} = require('@solana/web3.js');
const {
  getAssociatedTokenAddress,
  createAssociatedTokenAccountInstruction,
  createTransferInstruction,
  getAccount,
  TOKEN_PROGRAM_ID,
} = require('@solana/spl-token');
const fs = require('fs');

// 配置
const DEVNET_RPC = 'https://api.devnet.solana.com';
const TOKEN_MINT = '7uTpUhobocigTVnxF7Z8w5iGgEnxqn9gCm5Bazk5mW8i';

// 从环境变量或文件读取私钥
function loadKeypair(privateKeyPath) {
  try {
    if (fs.existsSync(privateKeyPath)) {
      const secretKey = JSON.parse(fs.readFileSync(privateKeyPath, 'utf8'));
      return Keypair.fromSecretKey(new Uint8Array(secretKey));
    }
  } catch (error) {
    console.error('无法加载私钥:', error.message);
  }
  return null;
}

// 生成新的测试钱包
function generateTestWallet() {
  const keypair = Keypair.generate();
  const secretKey = Array.from(keypair.secretKey);

  // 保存私钥到文件
  const walletData = {
    publicKey: keypair.publicKey.toString(),
    secretKey: secretKey,
  };

  fs.writeFileSync(
    `test-wallet-${Date.now()}.json`,
    JSON.stringify(walletData, null, 2),
  );

  return {
    keypair,
    publicKey: keypair.publicKey.toString(),
    secretKeyArray: secretKey,
  };
}

// 真实的代币购买函数
async function executeRealTokenPurchase(
  buyerKeypair,
  sellerKeypair,
  tokenAmount,
  solAmount,
) {
  console.log(`🎯 执行真实代币购买交易...\n`);

  const connection = new Connection(DEVNET_RPC, 'confirmed');
  const tokenMint = new PublicKey(TOKEN_MINT);

  const buyer = buyerKeypair.publicKey;
  const seller = sellerKeypair.publicKey;

  console.log(`📊 交易详情:`);
  console.log(`- 代币: ${TOKEN_MINT}`);
  console.log(`- 买家: ${buyer.toString()}`);
  console.log(`- 卖家: ${seller.toString()}`);
  console.log(`- 购买数量: ${tokenAmount} 代币`);
  console.log(`- 支付金额: ${solAmount} SOL\n`);

  try {
    // 检查余额
    const buyerBalance = await connection.getBalance(buyer);
    const sellerBalance = await connection.getBalance(seller);

    console.log(`💰 交易前余额:`);
    console.log(`- 买家: ${(buyerBalance / LAMPORTS_PER_SOL).toFixed(6)} SOL`);
    console.log(
      `- 卖家: ${(sellerBalance / LAMPORTS_PER_SOL).toFixed(6)} SOL\n`,
    );

    if (buyerBalance < solAmount * LAMPORTS_PER_SOL + 10000) {
      // 预留交易费
      throw new Error('买家SOL余额不足');
    }

    // 获取代币账户
    const sellerTokenAccount = await getAssociatedTokenAddress(
      tokenMint,
      seller,
    );
    const buyerTokenAccount = await getAssociatedTokenAddress(tokenMint, buyer);

    // 检查卖家代币余额
    let sellerTokenBalance;
    try {
      const account = await getAccount(connection, sellerTokenAccount);
      sellerTokenBalance = account.amount;
      console.log(`💎 卖家代币余额: ${sellerTokenBalance.toString()}`);

      if (sellerTokenBalance < BigInt(tokenAmount * Math.pow(10, 9))) {
        throw new Error('卖家代币余额不足');
      }
    } catch (error) {
      throw new Error('卖家没有此代币或余额不足');
    }

    // 检查买家代币账户
    let buyerAccountExists = false;
    try {
      await getAccount(connection, buyerTokenAccount);
      buyerAccountExists = true;
      console.log(`💎 买家代币账户已存在`);
    } catch (error) {
      console.log(`💎 买家代币账户不存在，将创建`);
    }

    console.log(`\n🔨 构建交易...`);

    // 创建交易
    const transaction = new Transaction();

    // 如果需要，创建买家代币账户
    if (!buyerAccountExists) {
      console.log(`📝 添加创建代币账户指令`);
      transaction.add(
        createAssociatedTokenAccountInstruction(
          buyer,
          buyerTokenAccount,
          buyer,
          tokenMint,
        ),
      );
    }

    // 添加代币转账指令（从卖家到买家）
    console.log(`📝 添加代币转账指令`);
    const tokenAmountWithDecimals = BigInt(tokenAmount * Math.pow(10, 9));
    transaction.add(
      createTransferInstruction(
        sellerTokenAccount,
        buyerTokenAccount,
        seller,
        tokenAmountWithDecimals,
      ),
    );

    // 添加SOL转账指令（从买家到卖家）
    console.log(`📝 添加SOL支付指令`);
    const { SystemProgram } = require('@solana/web3.js');
    transaction.add(
      SystemProgram.transfer({
        fromPubkey: buyer,
        toPubkey: seller,
        lamports: solAmount * LAMPORTS_PER_SOL,
      }),
    );

    // 设置交易参数
    const { blockhash } = await connection.getLatestBlockhash('confirmed');
    transaction.recentBlockhash = blockhash;
    transaction.feePayer = buyer;

    console.log(`\n🔏 签署交易...`);

    // 签署交易（需要买家和卖家都签署）
    transaction.partialSign(buyerKeypair, sellerKeypair);

    console.log(`📡 发送交易到区块链...`);

    // 发送并确认交易
    const signature = await sendAndConfirmTransaction(
      connection,
      transaction,
      [buyerKeypair, sellerKeypair],
      {
        commitment: 'confirmed',
        preflightCommitment: 'confirmed',
      },
    );

    console.log(`✅ 交易成功！`);
    console.log(`🔗 交易签名: ${signature}`);
    console.log(
      `🔍 查看交易: https://explorer.solana.com/tx/${signature}?cluster=devnet\n`,
    );

    // 检查交易后余额
    const newBuyerBalance = await connection.getBalance(buyer);
    const newSellerBalance = await connection.getBalance(seller);

    console.log(`💰 交易后余额:`);
    console.log(
      `- 买家: ${(newBuyerBalance / LAMPORTS_PER_SOL).toFixed(6)} SOL`,
    );
    console.log(
      `- 卖家: ${(newSellerBalance / LAMPORTS_PER_SOL).toFixed(6)} SOL`,
    );

    // 检查代币余额
    try {
      const newBuyerTokenAccount = await getAccount(
        connection,
        buyerTokenAccount,
      );
      const newSellerTokenAccount = await getAccount(
        connection,
        sellerTokenAccount,
      );

      console.log(`💎 代币余额:`);
      console.log(`- 买家: ${newBuyerTokenAccount.amount.toString()} 代币`);
      console.log(`- 卖家: ${newSellerTokenAccount.amount.toString()} 代币`);
    } catch (error) {
      console.log(`⚠️  无法获取代币余额`);
    }

    return {
      success: true,
      signature,
      txDetails: {
        tokenAmount,
        solAmount,
        buyer: buyer.toString(),
        seller: seller.toString(),
        timestamp: new Date().toISOString(),
      },
    };
  } catch (error) {
    console.error(`❌ 交易失败: ${error.message}`);
    return {
      success: false,
      error: error.message,
    };
  }
}

// 执行多笔交易的函数
async function executeBatchTrades(buyerKeypair, sellerKeypair, trades) {
  console.log(`🔥 开始执行 ${trades.length} 笔真实交易...\n`);

  const results = [];

  for (let i = 0; i < trades.length; i++) {
    const { tokenAmount, solAmount, description } = trades[i];

    console.log(`\n📈 交易 ${i + 1}/${trades.length}: ${description}`);
    console.log(`=====================================`);

    const result = await executeRealTokenPurchase(
      buyerKeypair,
      sellerKeypair,
      tokenAmount,
      solAmount,
    );

    results.push({
      tradeIndex: i + 1,
      description,
      ...result,
    });

    if (result.success) {
      console.log(`✅ 交易 ${i + 1} 成功完成`);
    } else {
      console.log(`❌ 交易 ${i + 1} 失败`);
    }

    // 交易间隔
    if (i < trades.length - 1) {
      console.log(`⏳ 等待 3 秒后执行下一个交易...`);
      await new Promise((resolve) => setTimeout(resolve, 3000));
    }
  }

  // 生成批量交易报告
  const successfulTrades = results.filter((r) => r.success);
  const failedTrades = results.filter((r) => !r.success);

  console.log(`\n📊 === 批量交易完成报告 ===`);
  console.log(`✅ 成功: ${successfulTrades.length}/${trades.length}`);
  console.log(`❌ 失败: ${failedTrades.length}/${trades.length}`);

  if (successfulTrades.length > 0) {
    console.log(`\n🔗 成功交易签名:`);
    successfulTrades.forEach((trade, index) => {
      console.log(`${index + 1}. ${trade.signature}`);
    });
  }

  if (failedTrades.length > 0) {
    console.log(`\n❌ 失败交易:`);
    failedTrades.forEach((trade, index) => {
      console.log(`${index + 1}. ${trade.description}: ${trade.error}`);
    });
  }

  return results;
}

// 使用示例
async function runExample() {
  console.log(`🚀 真实代币交易示例\n`);

  // 生成测试钱包
  console.log(`📝 生成测试钱包...`);
  const buyer = generateTestWallet();
  const seller = generateTestWallet();

  console.log(`👤 买家地址: ${buyer.publicKey}`);
  console.log(`👤 卖家地址: ${seller.publicKey}\n`);

  console.log(`⚠️  注意: 这些是新生成的测试地址，需要先获得SOL和代币才能交易`);
  console.log(`💡 建议: 使用现有的有余额的地址进行测试\n`);

  // 示例交易列表
  const trades = [
    { tokenAmount: 100, solAmount: 0.01, description: '小额测试交易' },
    { tokenAmount: 500, solAmount: 0.05, description: '中等交易' },
    { tokenAmount: 1000, solAmount: 0.1, description: '大额交易' },
  ];

  console.log(`📋 准备执行的交易:`);
  trades.forEach((trade, index) => {
    console.log(
      `${index + 1}. ${trade.description}: ${trade.tokenAmount} 代币 ← ${trade.solAmount} SOL`,
    );
  });

  console.log(`\n💡 要执行真实交易，请:`);
  console.log(`1. 确保买家有足够的SOL余额`);
  console.log(`2. 确保卖家有足够的代币余额`);
  console.log(`3. 使用真实的私钥文件`);
  console.log(`4. 在devnet环境中测试`);
}

// 命令行接口
if (require.main === module) {
  const command = process.argv[2];

  if (command === 'example') {
    runExample();
  } else if (command === 'execute') {
    const buyerKeyPath = process.argv[3];
    const sellerKeyPath = process.argv[4];
    const tokenAmount = parseFloat(process.argv[5]) || 100;
    const solAmount = parseFloat(process.argv[6]) || 0.01;

    if (!buyerKeyPath || !sellerKeyPath) {
      console.log(
        `用法: node real-token-trading.js execute <买家私钥文件> <卖家私钥文件> [代币数量] [SOL数量]`,
      );
      console.log(
        `示例: node real-token-trading.js execute buyer.json seller.json 1000 0.1`,
      );
      return;
    }

    const buyerKeypair = loadKeypair(buyerKeyPath);
    const sellerKeypair = loadKeypair(sellerKeyPath);

    if (!buyerKeypair || !sellerKeypair) {
      console.error(`❌ 无法加载私钥文件`);
      return;
    }

    executeRealTokenPurchase(
      buyerKeypair,
      sellerKeypair,
      tokenAmount,
      solAmount,
    );
  } else {
    console.log(`🎯 真实代币交易脚本`);
    console.log(`\n可用命令:`);
    console.log(`- example: 显示使用示例`);
    console.log(
      `- execute <买家私钥> <卖家私钥> [代币数量] [SOL数量]: 执行真实交易`,
    );
    console.log(`\n示例:`);
    console.log(`node real-token-trading.js example`);
    console.log(
      `node real-token-trading.js execute buyer.json seller.json 1000 0.1`,
    );
  }
}

module.exports = {
  executeRealTokenPurchase,
  executeBatchTrades,
  generateTestWallet,
  loadKeypair,
};
